/*
 * cashregister.cc
 *
 *  Created on: May 30, 2011
 *      Author: peckb1
 */

#include "cashregister.h"
#include "sharedDefinitions.h"

CashRegister::CashRegister(int registerId, int clerkId, Locks* allTheLocks) {
    myId = registerId;
    currentClerkId = clerkId;
    tillBalance = 0.0;
    currentCustomerBalance = 0.0;
    currentItemCount = 0;
    theLocks = allTheLocks;
}

CashRegister::~CashRegister() {
}

void CashRegister::DoWork() {
    bool scan = TRUE;
    Lock* registerStatusLock = theLocks->_registerLock[myId];
    Lock* registerInteractionLock = theLocks->_fromRegisterInteractionLock[myId];
    Lock* peopleWaitingCashLock = theLocks->_peopleWaitingForCashRegiterLock[myId];
    Condition* registerStatusCV = theLocks->_registerCV[myId];
    registerStatusLock->Acquire();
    theLocks->_managerEmtpyingTill[myId] =-1;
    while(true)
    {
		if (theLocks->_peopleWaitingForCashRegister[myId] > 0)
		{
			//People waiting for me, let them know i am available
			#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
				printf("CASH REGISTER #%i realizes there are %i people waiting for it. let one to start\n", myId, theLocks->_peopleWaitingForCashRegister[myId]);
			#endif
			(theLocks->_peopleWaitingForCashRegister[myId])--;
			if (theLocks->_clerkWantsToInteract[myId] == 0)
				theLocks->_clerkWantsToInteract[myId] = 1;
			else if (theLocks->_managerWantsToInteract[myId] == 0)
				theLocks->_managerWantsToInteract[myId] = 1;
			theLocks->_peopleWaitingForCashRegiterCV[myId]->Signal(registerStatusLock);
		}
		#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
			printf("CASH REGISTER #%i waiting for people to start interacting\n", myId);
		#endif
    	registerStatusCV->Wait(registerStatusLock);
		#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
			printf("CASH REGISTER #%i Just got a signal\n", myId);
		#endif
		if(theLocks->_managerEmtpyingTill[myId] == 0)
		{
			registerStatusLock->Release();
			#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
				printf("CASH REGISTER #%i start interacting with a clerk\n", myId);
			#endif
			registerInteractionLock->Acquire();
			#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
				printf("CASH REGISTER #%i clerk wants to scan items\n", myId);
			#endif
			InteractWithClerk();
			registerInteractionLock->Release();
		} else if(theLocks->_managerEmtpyingTill[myId] == 1)
		{
			registerStatusLock->Release();
			#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
				printf("CASH REGISTER #%i start interacting with manager\n", myId);
			#endif
			registerInteractionLock->Acquire();
			#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
				printf("CASH REGISTER #%i manager wants to empty till \n", myId);
			#endif
			//Let the others know I am free
			InteractWithManager();
			registerInteractionLock->Release();
		}
		registerStatusLock->Acquire();
		theLocks->_managerEmtpyingTill[myId] = -1;
		for (int tmp=0;tmp<10;tmp++)
			currentThread->Yield();
    }
    registerStatusLock->Release();
}

void
CashRegister::InteractWithClerk() {
    bool scanning = TRUE;
    //Lets reset our totals
    currentItemCount = 0;
    currentCustomerBalance = 0;
    // wake up the clerk and tell him we're ready for items
    Lock* registerLock = theLocks->_fromRegisterInteractionLock[myId];
    #ifdef PRINT_EXTRA_LOG_CASH_REGISTER
    	printf("CASH REGISTER #%i let the clerk know we are ready for next item\n", myId);
	#endif
    theLocks->_fromRegisterInteractionCV[myId]->Signal(registerLock);
	#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
		printf("CASH REGISTER #%i wait till next item be scanned\n", myId);
	#endif
    theLocks->_toRegisterInteractionCV[myId]->Wait(registerLock);
	#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
    	printf("CASH REGISTER #%i clerk just woke us up\n", myId);
	#endif
    Item* itemPurchased = theLocks->_itemToScan[myId];
    Item* itemRefunded = theLocks->_itemToRefund[myId];
    bool returning = false;
    while(itemPurchased != NULL || itemRefunded != NULL)
    {
    	if (itemPurchased != NULL)
    	{
			#ifdef PRINT_OUTPUT_CASH_REGISTER
    			printf("Cash Register [%i] got item [%i] from Clerk [%i] to scan.\n", myId, itemPurchased->getItemId(), currentClerkId);
			#endif
			currentCustomerBalance += itemPurchased->getPrice();
			theLocks->_itemToScan[myId] = NULL;
			currentItemCount++;
    	}
    	else if (itemRefunded != NULL)
		{
    		returning = true;
			#ifdef PRINT_OUTPUT_CASH_REGISTER
    			printf("Cash Register [%i] got item [%i] from Clerk [%i] to scan.\n", myId, itemRefunded->getItemId(), currentClerkId);
			#endif
    		currentCustomerBalance -= itemRefunded->getPrice();
    		theLocks->_itemToRefund[myId] = NULL;
    		currentItemCount++;
		}
		#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
			printf("CASH REGISTER #%i let the clerk know we are ready for next item\n", myId);
		#endif
			theLocks->_fromRegisterInteractionCV[myId]->Signal(registerLock);
		#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
			printf("CASH REGISTER #%i wait till next item be scanned\n", myId);
		#endif
			theLocks->_toRegisterInteractionCV[myId]->Wait(registerLock);
		#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
			printf("CASH REGISTER #%i clerk just woke us up\n", myId);
		#endif
    	itemPurchased = theLocks->_itemToScan[myId];
    	itemRefunded = theLocks->_itemToRefund[myId];
    }
    //All (or no) items have been scanned. Lets put the totals into
    //the shared variable and let the clerk know that he can grab it
	#ifdef PRINT_OUTPUT_CASH_REGISTER
		printf("Cash Register [%i] has scanned all [%i] items for Customer [%i].\n", myId, currentItemCount,theLocks->_customerBeingHelped[myId] );
	#endif
	theLocks->_moneyToTransfer[myId] = currentCustomerBalance;
	#ifdef PRINT_OUTPUT_CASH_REGISTER
		printf("Cash Register [%i] gave total cost $[%.2f] for Customer [%i] to Clerk[%i] for [%i] items.\n", myId, currentCustomerBalance ,theLocks->_customerBeingHelped[myId],myId,currentItemCount );
	#endif
	theLocks->_fromRegisterInteractionCV[myId]->Signal(registerLock);
	#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
		printf("CASH REGISTER #%i lets wait till we receive/pay the money\n", myId);
	#endif
	theLocks->_toRegisterInteractionCV[myId]->Wait(registerLock);
	#ifdef PRINT_OUTPUT_CASH_REGISTER
		if(returning)
			printf("Cash Register [%i] gave the money to Clerk [%i].\n", myId, myId );
		else
			printf("Cash Register [%i] got the money from Clerk [%i].\n", myId, myId );
	#endif
	//Customer paid/received the money, lets print receipt
	tillBalance += currentCustomerBalance;
	#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
		printf("CASH REGISTER #%i is printing receipt.\n", myId);
	#endif
	theLocks->_fromRegisterInteractionCV[myId]->Signal(registerLock);
	#ifdef PRINT_OUTPUT_CASH_REGISTER
		printf("Cash Register [%i] gave receipt to Clerk [%i] for Customer[%i].\n", myId, myId, theLocks->_customerBeingHelped[myId] );
	#endif
	#ifdef PRINT_OUTPUT_CASH_REGISTER
		printf("Cash Register [%i] total sale is $[%.2f].\n", myId,GetTotalSales()+tillBalance);
	#endif
	//registerLock->Release();
}

void
CashRegister::InteractWithManager() {
	// wake up the manager and tell him the total of the till
	Lock* registerLock = theLocks->_fromRegisterInteractionLock[myId];
	#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
		printf("CASH REGISTER #%i let the manager know that total till is %.2f\n", myId, tillBalance);
	#endif
	theLocks->_moneyToTransfer[myId] = tillBalance;
	theLocks->_fromRegisterInteractionCV[myId]->Signal(registerLock);
	#ifdef PRINT_EXTRA_LOG_CASH_REGISTER
		printf("CASH REGISTER #%i wait till manager picks up the till content\n", myId);
	#endif
	theLocks->_toRegisterInteractionCV[myId]->Wait(registerLock);
	IncreaseSales(tillBalance);
	tillBalance = 0;
	#ifdef PRINT_OUTPUT_CASH_REGISTER
		printf("Cash Register [%i] drawer has emptied by Manager.\n", myId );
	#endif
	#ifdef PRINT_OUTPUT_CASH_REGISTER
		printf("Cash Register [%i] total sale until now is $[%.2f].\n", myId,GetTotalSales());
	#endif

 }

